package com.auto.admin.manager.impl;

import cn.torna.sdk.client.OpenClient;
import cn.torna.sdk.common.Booleans;
import cn.torna.sdk.param.DebugEnv;
import cn.torna.sdk.param.DocItem;
import cn.torna.sdk.param.DocParamCode;
import cn.torna.sdk.param.DocParamHeader;
import cn.torna.sdk.param.DocParamReq;
import cn.torna.sdk.param.DocParamResp;
import cn.torna.sdk.request.DocCategoryCreateRequest;
import cn.torna.sdk.request.DocPushRequest;
import cn.torna.sdk.response.DocCategoryCreateResponse;
import cn.torna.sdk.response.DocPushResponse;
import com.auto.admin.constants.ApplicationNameCode;
import com.auto.admin.constants.Constants;
import com.auto.admin.constants.ModuleCategoryNameCode;
import com.auto.admin.entity.Module;
import com.auto.admin.entity.ModuleCategory;
import com.auto.admin.entity.bo.ApiInfoBO;
import com.auto.admin.manager.TornaDocPushManager;
import com.auto.admin.service.ModuleCategoryService;
import com.auto.admin.service.ModuleService;
import com.auto.admin.util.IdUtil;
import com.auto.api.common.exception.BusinessException;
import com.auto.api.common.utils.JsonMapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * Description:业务处理类
 *
 * @author liangshf
 * @date 2021-11-26
 */
@Service
public class TornaDocPushManagerImpl implements TornaDocPushManager, InitializingBean {

    @Resource
    private ModuleService moduleService;

    @Resource
    private ModuleCategoryService moduleCategoryService;

    private static final Logger logger = LoggerFactory.getLogger(TornaDocPushManagerImpl.class);

    @Value("${torna.push.url}")
    private String url;

    private static OpenClient client;

    @Override
    public void afterPropertiesSet() throws Exception {
        client = new OpenClient(url);
    }

    @Async
    public void pushTornaDoc(List<ApiInfoBO> mockMappingList) {
        String applicationName = mockMappingList.get(0).getApplicationName();
        //查询应用对应模块
        Module module = moduleService.getByCode(applicationName);
        if (Objects.isNull(module) || StringUtils.isEmpty(module.getToken())) {
            throw new BusinessException("请配置模块:%s,TOKEN").args(applicationName);
        }
        List<ModuleCategory> categoryList = checkModuleCategoryList(mockMappingList, module);
        saveModuleCategoryList(categoryList, module);
        //推送TORNA文档
        pushTornaApiDoc(mockMappingList ,categoryList, module);
    }


    /**
     * 验证及组装新增ApiCategory信息
     *
     * @param mockMappingList List<SaveApiInfoBO>
     * @param module Module
     * @return List
     */
    private List<ModuleCategory> checkModuleCategoryList(List<ApiInfoBO> mockMappingList, Module module) {
        //旧ApiCategory
        Map<String, ModuleCategory> oldApiCategoryMap = Collections.emptyMap();
        if (CollectionUtils.isNotEmpty(mockMappingList)) {
            //获取所有分类
            List<ModuleCategory> categoryList = moduleCategoryService.findByModuleId(module.getId());
            if (CollectionUtils.isNotEmpty(categoryList)) {
                oldApiCategoryMap = categoryList.stream().collect(Collectors.toMap(ModuleCategory::getCode, Function.identity()));
            }
        }
        String applicationName = mockMappingList.get(0).getApplicationName();
        Set<String> codeList = mockMappingList.parallelStream().map(v -> {
            String controllerName = v.getControllerName();
            String [] codes = controllerName.split(Constants.POINT);
            return codes[codes.length -2];
        }).collect(Collectors.toSet());
        // 组装ApiCategory信息
        List<ModuleCategory> result = new ArrayList<>();
        for (String code : codeList) {
            String applicationCode = applicationName + "_" + code;
            ModuleCategory category = oldApiCategoryMap.remove(applicationCode);
            if (category == null) {
                category = new ModuleCategory();
                category.setId(null);
                category.setName(ModuleCategoryNameCode.getDesc(code));
                category.setCode(applicationCode);
                category.setModuleId(module.getId());
            }
            result.add(category);
        }
        return result;
    }

    /**
     * 保存ApiCategory信息
     *
     * @param moduleCategoryList List<ModuleCategory>
     * @param module Module
     */
    private void saveModuleCategoryList(List<ModuleCategory> moduleCategoryList, Module module) {
        DocCategoryCreateRequest request = null;
        for (ModuleCategory category : moduleCategoryList) {
            if (category.getId() == null) {
                if (request == null) {
                    request = new DocCategoryCreateRequest(module.getToken());
                }
                request.setName(category.getName() == null ? category.getCode() : category.getName());
                // 发送请求
                DocCategoryCreateResponse response = client.execute(request);
                if (response.isSuccess()) {
                    // 返回结果
                    category.setTornaCategoryId(IdUtil.decode(response.getData().getId()));
                } else {
                    logger.error("errorCode:" + response.getCode() + ",errorMsg:" + response.getMsg());
                    throw new BusinessException("分类创建异常");
                }
                moduleCategoryService.save(category);
            }
        }
    }

    /**
     *
     * pushTornaApiDoc
     * @param apiInfoList    List<ApiInfoBO>
     * @param categoryList List<ModuleCategory>
     * @param module Module
     */
    private void pushTornaApiDoc(List<ApiInfoBO> apiInfoList ,List<ModuleCategory> categoryList, Module module) {
        DocPushRequest request = new DocPushRequest(module.getToken());
        Map<String, ModuleCategory> apiCategoryMap = categoryList.stream().collect(Collectors.toMap(ModuleCategory::getCode, Function.identity()));
        List<DocItem> items = Lists.newArrayListWithCapacity(apiInfoList.size());
        Integer port = null;
        for (ApiInfoBO mapping : apiInfoList) {
            ModuleCategory moduleCategory = apiCategoryMap.get(module.getCode() + "_" + mapping.getSmallCode());
            items.add(buildDocItem(mapping, moduleCategory));
            if (port == null) {
                port = mapping.getPort();
            }
        }
        request.setApis(items);
        request.setAuthor("liangshf");
        request.setIsReplace(Booleans.TRUE);
        setDebugEnv(request, module, port);
        // 发送请求
        DocPushResponse response = client.execute(request);
        if (response.isSuccess()) {
            // 返回结果
            logger.info("pushTornaApiDoc请求成功");
        } else {
            logger.error("errorCode:" + response.getCode() + ",errorMsg:" + response.getMsg());
        }
    }

    private void setDebugEnv(DocPushRequest request, Module module, Integer port) {
        //获取网关转发路径
        String gateWayApi = ApplicationNameCode.getDesc(module.getCode());
        List<DebugEnv> debugEnvs = Lists.newArrayList();
        DebugEnv local = new DebugEnv("local", "http://192.168.1.84:" + port, "2");
        debugEnvs.add(local);
        DebugEnv debugEnv = new DebugEnv("dev01", "https://dev/api/" + gateWayApi, "2");
        debugEnvs.add(debugEnv);
        DebugEnv qa01 = new DebugEnv("qa01", "https://qa01/api/" + gateWayApi, "2");
        debugEnvs.add(qa01);
        DebugEnv uat = new DebugEnv("uat", "https://uat/api/" + gateWayApi, "2");
        debugEnvs.add(uat);
        DebugEnv prd = new DebugEnv("prd", "https://prd/api/" + gateWayApi, "2");
        debugEnvs.add(prd);
        request.setDebugEnvs(debugEnvs);
    }

    private static DocItem buildDocItem(ApiInfoBO apiInfo, ModuleCategory moduleCategory) {
        DocItem item = new DocItem();
        item.setAuthor("liangshf");
        /* 设置基本信息 */
        item.setName(StringUtils.isEmpty(apiInfo.getMethodRmk()) ? (StringUtils.isEmpty(apiInfo.getControllerRmk()) ? apiInfo.getMethodName() : apiInfo.getControllerRmk()) : apiInfo.getMethodRmk());
        item.setDescription(StringUtils.isEmpty(apiInfo.getMethodRmk()) ? apiInfo.getControllerRmk() : apiInfo.getMethodRmk());
        if (StringUtils.isEmpty(item.getDescription())) {
            item.setDescription("Api Class：" + apiInfo.getControllerName());

        } else {
            item.setDescription(item.getDescription() + " Api Class：" + apiInfo.getControllerName());
        }
        item.setUrl(apiInfo.getRequestUrl());
        item.setHttpMethod(apiInfo.getRequestType());
        item.setContentType("application/json");
        item.setParentId(moduleCategory == null ? "" : moduleCategory.getTornaCategoryId().toString());
        item.setType((byte) 0);
        item.setIsShow(Booleans.TRUE);
        item.setIsFolder(Booleans.FALSE);
        //设置公共请求头
        List<DocParamHeader> headerParams = Lists.newArrayList();
        DocParamHeader header = new DocParamHeader();
        header.setName("token");
        header.setDescription("登录凭证");
        headerParams.add(header);
        DocParamHeader channelId = new DocParamHeader();
        channelId.setName("channel-id");
        channelId.setDescription("channelId");
        headerParams.add(channelId);
        DocParamHeader userId = new DocParamHeader();
        userId.setName("userId");
        userId.setDescription("userId");
        headerParams.add(userId);
        item.setHeaderParams(headerParams);

        /* 设置Query参数 */
        if (apiInfo.getRequestType().equals("GET") && StringUtils.isNotEmpty(apiInfo.getTornaParamApiJson())) {
            List<DocParamReq> paramList = JsonMapper
                .fromJson(apiInfo.getTornaParamApiJson(), JsonMapper.constructCollectionType(List.class, DocParamReq.class));
            item.setQueryParams(paramList);
        }

        /* 设置请求参数 */
        if (apiInfo.getRequestType().equals("POST") && StringUtils.isNotEmpty(apiInfo.getTornaParamApiJson())) {
            List<DocParamReq> paramList = JsonMapper.fromJson(apiInfo.getTornaParamApiJson(), JsonMapper.constructCollectionType(List.class, DocParamReq.class));
            item.setRequestParams(paramList);
        }

        /* 设置返回参数 */
        if (StringUtils.isNotEmpty(apiInfo.getTornaResultApiJson())) {
            List<DocParamResp> respList = JsonMapper.fromJson(apiInfo.getTornaResultApiJson(), JsonMapper.constructCollectionType(List.class, DocParamResp.class));
            item.setResponseParams(respList);
        }
        /* 设置错误码 */
        DocParamCode code = new DocParamCode();
        code.setCode("10001");
        code.setMsg("token错误");
        code.setSolution("请传token");
        item.setErrorCodeParams(Arrays.asList(code));
        return item;
    }

}
